package io.github.cocoa.module.socket.handler;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.BroadcastOperations;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import io.github.cocoa.module.socket.enums.NettySocketIoConstants;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 消息事件处理程序
 *
 * @author Chim
 * @since 2024/12/12
 */
@Slf4j
@Component
public class MessageEventHandler {

    public static ConcurrentMap<String, SocketIOClient> socketIOClientMap = new ConcurrentHashMap<>();


    @Resource
    private RedissonClient redissonClient;
    @Resource
    private SocketIOServer socketIOServer;

    /**
     * 连接时触发
     *
     * @param client SocketIOClient
     * @see com.corundumstudio.socketio.listener.ConnectListener
     */
    @OnConnect
    public void onConnect(SocketIOClient client) {
        JSONObject clientObj = new JSONObject();
        if (client != null) {
            String sessionId = client.getSessionId().toString();
            if (StrUtil.isNotBlank(sessionId)) {
                client.joinRoom(sessionId);
                clientObj.set("room", sessionId);
            }
            clientObj.set("createTime", LocalDateTime.now().toString());
            // 存储会话消息
            RMap<String, JSONObject> clientMap = redissonClient.getMap(StrUtil.format(NettySocketIoConstants.ROOM_KEY, sessionId));
            clientMap.putIfAbsent(sessionId, clientObj);
            int size = socketIOServer.getAllClients().size();
            log.info("@OnConnect 连接成功, size:{}, sessionId: {}", size, sessionId);
        }
    }

    /**
     * 断开连接时触发
     *
     * @param client SocketIOClient
     * @see com.corundumstudio.socketio.listener.DisconnectListener
     */
    @OnDisconnect
    public void onDisconnect(SocketIOClient client) {
        String sessionId = client.getSessionId().toString();
        // 删除会话消息
        RMap<String, JSONObject> clientMap = redissonClient.getMap(StrUtil.format(NettySocketIoConstants.ROOM_KEY, sessionId));
        clientMap.remove(sessionId);
        int size = socketIOServer.getAllClients().size();
        log.info("@OnDisconnect 断开连接, size:{}, sessionId: {}", size, sessionId);
    }

    /**
     * 客户端事件
     *
     * @param client    接收器
     * @param data      接收对象
     * @param ackSender ack请求
     * @see com.corundumstudio.socketio.listener.DataListener
     */
    @OnEvent(value = "message")
    public void onMessageEvent(SocketIOClient client, Object data, AckRequest ackSender) {
        UUID sessionId = client.getSessionId();
        log.info("@onMessageEvent sessionId: {}, data: {}", sessionId, data);

        RMap<String, JSONObject> clientMap = redissonClient.getMap(StrUtil.format(NettySocketIoConstants.ROOM_KEY, sessionId));
        // 单房广播操作
        // socketIOServer.getRoomOperations("{to}").sendEvent("message", data);
        // 多房间广播操作
        BroadcastOperations operations = socketIOServer.getBroadcastOperations();
        log.info("@onMessageEvent size: {} operations: {}", operations.getClients().size(), operations);
        operations.sendEvent("message", data);

    }

    /**
     * 加入房间事件
     *
     * @param client    接收器
     * @param data      接收对象
     * @param ackSender ack请求
     * @see com.corundumstudio.socketio.listener.DataListener
     */
    @OnEvent(value = "join_room")
    public void onJoinRoomEvent(SocketIOClient client, String data, AckRequest ackSender) {
        UUID sessionId = client.getSessionId();
        log.info("@onJoinRoomEvent sessionId: {}, data: {}", sessionId, data);

        client.joinRoom(data);
        BroadcastOperations operations = socketIOServer.getRoomOperations(data);
        log.info("@onJoinRoomEvent size: {} operations: {}", operations.getClients().size(), operations);
        operations.sendEvent("join_room", sessionId);
    }

}